﻿using System;
using System.ComponentModel.Composition;
using System.IO;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Markup;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;

using Microsoft.SharePoint.Client;

using ESRI.ArcGIS.Client;
using ESRI.ArcGIS.Client.Extensibility;

namespace SymbolAssociationCommand
{

    /// <summary>
    /// Simple ArcGIS SharePoint command to associate a symbol list with a
    /// particular layer.
    /// </summary>
    [Export( typeof( ICommand ) )]
    [DisplayName( "MASAS Symbols" )]
    public class SymbolAssociationCommand : ICommand
    {

        // Internal Members...
        private SelectLayerDialog   dialog          = null;
        private Map                 map             = null;
        private Layer               selectedLayer   = null;
        private Site                site            = null;
        private WebClient           client          = new WebClient();

        /// <summary>
        /// Occurs when changes occur that affect whether the command should execute.
        /// </summary>
        public event EventHandler CanExecuteChanged;

        /// <summary>
        /// Defines the method to be called when the command is invoked.
        /// </summary>
        /// <param name="parameter">Data used by the command. If the command does not require data to be passed, this object can be set to null.</param>
        public void Execute( object parameter )
        {
            map = MapApplication.Current.Map;

            // Instantiate a new dialog if one does not already exist
            dialog = dialog ?? new SelectLayerDialog( MapApplication.Current.Map as ESRI.ArcGIS.Client.Map );
            
            // Display the dialog
            dialog.Closed += new EventHandler( dialog_Closed );
            dialog.Show();            
        }

        /// <summary>
        /// Handles the Closed event of the dialog control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        void dialog_Closed( object sender, EventArgs e )
        {
            dialog.Closed -= new EventHandler( dialog_Closed );

            selectedLayer = dialog.SelectedLayer;

            if( dialog.DialogResult == true )
            {
                ApplySymbols();
            }
        }

        /// <summary>
        /// Defines the method that determines whether the command can execute in its current state.
        /// </summary>
        /// <param name="parameter">Data used by the command. If the command does not require data to be passed, this object can be set to null.</param>
        /// <returns>
        /// true if this command can be executed; otherwise, false.
        /// </returns>
        public bool CanExecute( object parameter )
        {
            // Return true so that the command is always enabled
            return MapApplication.Current.Map != null;
        }

        /// <summary>
        /// Starts the process to apply the symbology lookup to the selected layer.
        /// </summary>
        private void ApplySymbols()
        {           
            // We need the Site Collection's URL...
            ClientContext clientContext = ClientContext.Current;
            site = clientContext.Site;
            clientContext.Load( site );
            clientContext.ExecuteQueryAsync( onExecuteSuccess, onExecuteFailure );
        }

        /// <summary>
        /// Ons the execute success.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="args">The <see cref="Microsoft.SharePoint.Client.ClientRequestSucceededEventArgs"/> instance containing the event data.</param>
        private void onExecuteSuccess( Object sender, ClientRequestSucceededEventArgs args )
        {
            // Now we can load the symbols, but first we need to go back to the original thread...
            dialog.Dispatcher.BeginInvoke( LoadSymbols );
        }

        /// <summary>
        /// Ons the execute failure.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="args">The <see cref="Microsoft.SharePoint.Client.ClientRequestFailedEventArgs"/> instance containing the event data.</param>
        private void onExecuteFailure( Object sender, ClientRequestFailedEventArgs args )
        {

        }

        /// <summary>
        /// Loads the symbols.
        /// </summary>
        private void LoadSymbols()
        {
            client.OpenReadCompleted += new OpenReadCompletedEventHandler( client_OpenReadCompleted );
            client.OpenReadAsync( new Uri( site.Url + "/MASASDocuments/EmergencyMappingSymbology.xaml", UriKind.Absolute ) );
        }

        /// <summary>
        /// Completes the process of applying the symbology lookups to the selected layer.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Net.OpenReadCompletedEventArgs"/> instance containing the event data.</param>
        void client_OpenReadCompleted( object sender, OpenReadCompletedEventArgs e )
        {
            client.OpenReadCompleted -= new OpenReadCompletedEventHandler( client_OpenReadCompleted );

            if( e.Error != null )
            {
                if( e.Error is WebException )
                {
                    dialog.Dispatcher.BeginInvoke( showErrorMessage );
                }
                else
                {
                    dialog.Dispatcher.BeginInvoke( showUnknownErrorMessage );
                }
            }
            else
            {
                // Read the data from the stream into a string...
                StreamReader myReader = new StreamReader( e.Result );
                string xaml = myReader.ReadToEnd();
                myReader.Close();

                if( xaml != null && selectedLayer != null )
                {
                    GraphicsLayer gLayer = selectedLayer as GraphicsLayer;
                    UniqueValueRenderer uvRender = ( gLayer.Renderer as UniqueValueRenderer );

                    if( uvRender == null )
                    {
                        uvRender = new UniqueValueRenderer();
                        uvRender.Field = "MASAS_SymbolID";
                        gLayer.Renderer = uvRender;
                    }

                    // Create a resource dictionnary from the given xaml...
                    ResourceDictionary rd = (ResourceDictionary)XamlReader.Load( xaml );

                    // Clear the existing lookup information...
                    uvRender.Infos.Clear();

                    // Add a new entry for every symbol in the dictionnary...
                    foreach( string curKey in rd.Keys )
                    {
                        ESRI.ArcGIS.Client.Symbols.Symbol symbol = rd[curKey] as ESRI.ArcGIS.Client.Symbols.Symbol;
                        uvRender.Infos.Add( new UniqueValueInfo() { Symbol = symbol, Value = curKey } );
                    }
                }
            }
        }

        /// <summary>
        /// Shows the error message.
        /// </summary>
        void showErrorMessage()
        {
            MessageBox.Show( "The MASAS tool could not find the file EmergencyMappingSymbology.xaml." + Environment.NewLine + "Please verify your configuration and try again.", "MASAS - ERROR", MessageBoxButton.OK );
        }

        /// <summary>
        /// Shows the unknown error message.
        /// </summary>
        void showUnknownErrorMessage()
        {
            MessageBox.Show( "The MASAS tool has encountered an unknown error!", "MASAS - ERROR", MessageBoxButton.OK );
        }

    }

}
